import groovy.mock.interceptor.MockFor
import javax.swing.JPanel
import net.yiny.scrummer.model.Card
import net.yiny.scrummer.ui.storyboard.CardBuilder
import net.yiny.scrummer.ui.storyboard.CardController
import static org.hamcrest.MatcherAssert.assertThat
import static org.hamcrest.Matchers.is

CardController controller
def mockBuilder
def mockCard
Helper helper

class Helper {
    def mockBuilder
    def mockCard
    def controller

    def basicMockCard() {
        mockCard.demand.getName() {'TestName'}
        mockCard.demand.getId() {1}
        mockCard.demand.getDescription() {'Test Description'}
    }

    def demandBuilderReadCard() {
        mockBuilder.demand.setName() {assertThat it, is('TestName')}
        mockBuilder.demand.setId() {assertThat it.toString(), is('#1')} //GString to String
        mockBuilder.demand.setDescription() {assertThat it, is('Test Description')}
    }

    def doWithCardAndBuilder(closure) {
        controller.builder = mockBuilder.proxyInstance()
        controller.card = mockCard.proxyInstance()
        closure()
        mockCard.verify controller.card
        mockBuilder.verify controller.builder
    }
}

before_each 'set up the controller object and the mocks to use', {
    controller = new CardController()
    mockBuilder = new MockFor(CardBuilder)
    mockCard = new MockFor(Card)
    helper = new Helper(mockBuilder: mockBuilder, mockCard: mockCard, controller: controller)
}

scenario '''the controller should read the card properties upon initialisation, it should also
            initialise the builder and give it the information it read from the card
            and return the panel it received from the builder''', {
    def panel
    given 'a card that has been mocked, and a panel which will be returned from the mock builder', {
        helper.basicMockCard()
        panel = new JPanel()
        mockBuilder.demand.initialise {panel}
        helper.demandBuilderReadCard()
    }
    then 'initialising the card should execute all the expected functionality', {
        helper.doWithCardAndBuilder({assertThat controller.initialise(), is(panel)})
    }
}

scenario 'initialising a controller without a card or builder should throw an ISE', {
    when 'the controller that has a null card and builder is initialised', {
        wasThrown = true
        ensureThrows(IllegalStateException) {
            controller.initialise()
            wasThrown = false
        }
    }
    then 'an exception should have been thrown', {
        wasThrown.shouldBe true
    }
}

scenario 'initialising a controller with a null card should throw an ISE', {
    given 'that the controller only has the builder set', {
        controller.builder = new CardBuilder()
    }
    when 'the controller is initialised', {
        wasThrown = true
        ensureThrows(IllegalStateException) {
            controller.initialise()
        }
    }
    then 'an exception should have been thrown', {
        wasThrown.shouldBe true
    }
}

scenario 'initialising a controller with a null builder should throw an ISE', {
    given 'that the controller only has a card set', {
        controller.card = new Card()
    }
    when 'the controller is initialised', {
        wasThrown = true
        ensureThrows(IllegalStateException) {
            controller.initialise()
        }
    }
    then 'an exception should have been thrown', {
        wasThrown.shouldBe true
    }
}

scenario 'setting the card property on the controller works correctly', {
    Card card
    given 'a card object', {
        card = new Card()
    }
    when 'the object is set to the controller', {
        controller.card = card
    }
    then 'the saved object should be identical', {
        controller.card.shouldBe card
    }
}

scenario 'updating the controller should re-read information from the card and set it to the builder', {
    when 'we update the card, it should read the information from the card into the builder', {
        helper.basicMockCard()
        helper.demandBuilderReadCard()
        helper.doWithCardAndBuilder({controller.updateCard()})
    }
}
